package top.likeqc.moneymark.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.likeqc.moneymark.common.dto.BillDTO;
import top.likeqc.moneymark.common.lang.Result;
import top.likeqc.moneymark.entity.Account;
import top.likeqc.moneymark.entity.Bill;
import top.likeqc.moneymark.entity.Book;
import top.likeqc.moneymark.entity.Catename;
import top.likeqc.moneymark.service.*;
import top.likeqc.moneymark.util.ShiroUtil;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 账单 前端控制器 核心接口
 *
 * @author likeqc.top
 * @since 2021-07-03
 */
@RestController
@RequestMapping("/bill")
public class BillController {

    @Autowired BillService billService;
    @Autowired TypeService typeService;
    @Autowired CatenameService catenameService;
    @Autowired BookService bookService;
    @Autowired AccountService accountService;

    /**
     * 根据时间查询历史账单
     *
     * @param year 年（YYYY）
     * @param month 月（MM）
     * @param day 日（DD）
     * @return 指定时间的所有历史账单（按时间倒序排序）
     */
    @GetMapping({"/{year}/{month}/{day}", "/{year}/{month}", "/{year}", ""})
    @RequiresAuthentication
    public Result getByDate(
            @PathVariable(required = false) Integer year,
            @PathVariable(required = false) Integer month,
            @PathVariable(required = false) Integer day) {
        Integer userid = ShiroUtil.getProfile().getId();
        StringBuffer date = new StringBuffer();
        // 加上前导 0
        if (year != null) {
            date.append(year);
        }
        if (month != null) {
            if (month < 10) {
                date.append("-0" + month);
            } else {
                date.append("-" + month);
            }
        }
        if (day != null) {
            if (day < 10) {
                date.append("-0" + day);
            } else {
                date.append("-" + day);
            }
        }

        date.append("%");
        System.out.println("时间字符串: " + date.toString());
        List<Bill> bills =
                billService.list(
                        new QueryWrapper<Bill>()
                                .eq("user_id", userid)
                                .like("time", date.toString())
                                .orderByDesc("time"));
        List<BillDTO> billDTOList = Bill2BillDTO(bills);
        return Result.succ("查询成功", billDTOList);
    }

    /**
     * 删除账单
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    @RequiresAuthentication
    public Result deleteById(@PathVariable Long id) {
        Integer userid = ShiroUtil.getProfile().getId();
        Bill bill = billService.getById(id);
        Assert.isTrue(userid.equals(bill.getUserId()), "您不是该账单的拥有者");
        billService.removeById(id);
        return Result.succ("删除账单成功", bill);
    }

    /**
     * 添加或修改一笔账单，有 id 修改，无 id 新增
     *
     * @param billDTO
     * @return
     */
    @PostMapping()
    @RequiresAuthentication
    public Result editBill(@RequestBody @Validated BillDTO billDTO) {
        // System.out.println("接收到的账单DTO：" + billDTO);
        Integer userid = ShiroUtil.getProfile().getId();
        Bill bill = billDto2Bill(billDTO);
        String msg;
        if (billDTO.getId() != null) {
            Bill bill1 = billService.getById(billDTO.getId());
            Assert.notNull(bill1, "没有 id=" + billDTO.getId() + " 的账单");
            Assert.isTrue(userid.equals(bill1.getUserId()), "您不是 id=" + billDTO.getId() + " 的拥有者");
            billService.updateById(bill);
            msg = "更新成功";
        } else {
            billService.save(bill);
            msg = "新增成功";
        }
        return Result.succ(msg, bill);
    }

    private Bill billDto2Bill(BillDTO billDTO) {
        Integer userid = ShiroUtil.getProfile().getId();
        if (billDTO.getTime() == null || billDTO.getTime().trim().length() == 0) {
            billDTO.setTime(LocalDateTime.now().toString());
        }
        if (billDTO.getCatename() == null || billDTO.getCatename().trim().length() == 0) {
            billDTO.setCatename("默认分类");
        }
        if (billDTO.getBookname() == null || billDTO.getBookname().trim().length() == 0) {
            billDTO.setBookname("默认账本");
        }
        if (billDTO.getAccountname() == null || billDTO.getAccountname().trim().length() == 0) {
            billDTO.setAccountname("默认账户");
        }

        Catename catename =
                catenameService.getOne(
                        new QueryWrapper<Catename>()
                                .eq("user_id", userid)
                                .eq("name", billDTO.getCatename()));
        Book book =
                bookService.getOne(
                        new QueryWrapper<Book>()
                                .eq("user_id", userid)
                                .eq("name", billDTO.getBookname()));
        Account account =
                accountService.getOne(
                        new QueryWrapper<Account>()
                                .eq("user_id", userid)
                                .eq("name", billDTO.getAccountname()));
        Assert.notNull(catename, "发生错误！账单分类【" + billDTO.getCatename() + "】不存在");
        Assert.notNull(book, "发生错误！账本【" + billDTO.getBookname() + "】不存在");
        Assert.notNull(account, "发生错误！资产账户【" + billDTO.getAccountname() + "】不存在");

        Bill bill = new Bill();
        bill.setUserId(userid)
                .setId(billDTO.getId())
                .setTypeId(billDTO.getType())
                .setCatenameId(catename.getId())
                .setBookId(book.getId())
                .setAccountId(account.getId())
                .setMoney(new BigDecimal(billDTO.getMoney()))
                .setTime(LocalDateTime.parse(billDTO.getTime()))
                .setRemark(billDTO.getRemark());
        return bill;
    }

    // TODO: 直接使用多表查询得到 BillDTO 数据，避免多次操作数据库
    // select bill.id id, type.`name` type, bill.`money` money, time, remark, catename.`name`
    // catename, account.`name` accountname, book.`name` bookname  from bill
    // left join type on bill.`type_id`= type.`id`
    // left join catename on bill.`catename_id` = catename.`id`
    // left join book on bill.`book_id` = book.`id`
    // left join account on bill.`account_id` = account.`id`
    private List<BillDTO> Bill2BillDTO(List<Bill> bills) {
        Integer userid = ShiroUtil.getProfile().getId();
        ArrayList<BillDTO> billDTOList = new ArrayList<>();
        Map<Integer, String> catenameMap = new HashMap<>();
        Map<Integer, String> accountnameMap = new HashMap<>();
        Map<Integer, String> booknameMap = new HashMap<>();
        List<Catename> catenameList =
                catenameService.list(new QueryWrapper<Catename>().eq("user_id", userid));
        for (Catename c : catenameList) {
            catenameMap.put(c.getId(), c.getName());
        }
        List<Account> accountList =
                accountService.list(new QueryWrapper<Account>().eq("user_id", userid));
        for (Account a : accountList) {
            accountnameMap.put(a.getId(), a.getName());
        }
        List<Book> bookList = bookService.list(new QueryWrapper<Book>().eq("user_id", userid));
        for (Book c : bookList) {
            booknameMap.put(c.getId(), c.getName());
        }

        for (Bill bill : bills) {
            BillDTO billDTO = new BillDTO();
            billDTO.setId(bill.getId());
            billDTO.setType(bill.getTypeId());
            billDTO.setMoney(Double.parseDouble(bill.getMoney().toString()));
            billDTO.setTime(bill.getTime().toString());
            billDTO.setRemark(bill.getRemark());
            billDTO.setCatename(catenameMap.get(bill.getCatenameId()));
            billDTO.setAccountname(accountnameMap.get(bill.getAccountId()));
            billDTO.setBookname(booknameMap.get(bill.getBookId()));
            billDTOList.add(billDTO);
        }
        return billDTOList;
    }
}
